home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Hacks / Hacks ’92 / Savvy ƒ / SavvyInit.c < prev    next >
Encoding:
Text File  |  1992-06-20  |  10.9 KB  |  349 lines  |  [TEXT/MPS ]

  1. /* @(#) SavvyInit.c 6/19/92
  2.     {Sources}Hack:SavvyInit.c
  3.  
  4.     No rights reserved
  5.     
  6.     Product:        Joel’s MacHack ’92 entry
  7.     File:            SavvyInit.c
  8.     Author:            Joel West, Palomar Software
  9.     Date:            Wed, Jun 17, 1992
  10.     Description:    Code for “Savvy” Extension (INIT)
  11.  
  12.  
  13. TO DO:
  14.     Invalidate Finder cache so we are displayed every time
  15.     Handle updates (so icon is displayed after window is covered)
  16.     Crimp clipregion to icon size
  17.     test on non color QD
  18.  
  19.     Entry category (with apologies to the Emmies):
  20.         Serious, Apple Marketing Politically Correct, first hack written
  21.         by a manager while at MacHack that include source.
  22.  
  23.     Sources:
  24.         IsSavvyTool.c    stand-alone testbench (not otherwised used)
  25.         IconSuite.h        System 7 icon utilities from TN #306
  26.         Savvy.a            glue for trap patches
  27.         Savvy.h            header for C, Rez
  28.         Savvy.make        Makefile for everything
  29.         SavvyInit.c        code for the INIT and trap patches
  30.         SavvyInit.r        resources for the INIT
  31.         ShowINIT.a        standard developer CD 
  32.     Usage:
  33.         BuildProgram Savvy
  34. */
  35.  
  36. #undef qCheckHeapUsage
  37.  
  38. #include <Traps.h>
  39. #include <GestaltEqu.h>
  40. #include <Events.h>
  41. #include <OSUtils.h>
  42. #include <ToolUtils.h>
  43. #include <Memory.h>
  44. #include <Resources.h>
  45. #include <Errors.h>
  46. #include <string.h>
  47. #include "Savvy.h"
  48.  
  49. #ifdef qUseIconSuite
  50. # include "IconSuite.h"
  51. #endif qUseIconSuite
  52.  
  53. #define PRIVATE static
  54. PRIVATE Handle GetDetachRsrc(OSType thetype,Integer theid);
  55. PRIVATE void PlotSavviness(TGlobalsPtr gptr);
  56. PRIVATE void DimRect(Integer top,Integer left, Integer bottom,Integer right);
  57. #ifdef qUseIconSuite
  58. PRIVATE OSErr PopulateIconSuite(Integer resid,Handle *psuiteh);
  59. #endif qUseIconSuite
  60.  
  61. /*
  62.     Biggest problem:
  63.         The biggest problem is that the Finder caches the information so
  64.             we are not displayed on the second “Get Info” for the same
  65.             application, UNLESS you close the folder window in between
  66.             Get Info to flush the cache.  The work-around should probably
  67.             be to implement a comparable cache here.  Or better yet,
  68.             just touch the mod date of the parent folder, which
  69.             invalidates the cache.
  70.     Another biggie:
  71.         The general approach for fooling the Finder is suitable only for a
  72.             one-time tool (but then it is a 2-day hack, not a product…)
  73. */
  74. /* Install the trap patches to make this all work, UNLESS:
  75.         1) Not System 7; or
  76.         2) Holding down Command key
  77.     Note: we need to make sure the info we need is properly loaded and
  78.     stashed in the system heap, so it will be available later.
  79. */
  80. void InitEntry(void)
  81. {    long attribute=0;
  82.  
  83. #ifdef qCheckHeapUsage
  84.     DebugStr("\p;HX @SysZone;HT;G");
  85. #endif qCheckHeapUsage
  86. /* Check for Apple Events present, since those are the most interesting we check for */
  87.     if (Gestalt(gestaltAppleEventsAttr,&attribute) == noErr &&
  88.         attribute & (1<<gestaltAppleEventsPresent)) {
  89.         KeyMap thekeys;
  90.  
  91.         GetKeys(thekeys);
  92.         if (!(thekeys[1] & 0x008000)) {
  93.             TGlobalsPtr gptr;
  94.             ShowINIT(kICNN_DoSavvy,kShowInitStdOffset);
  95.  
  96.             (void) GetDetachRsrc('INIT',0);
  97.             gptr = GetGlobals();
  98.             gptr->lastSizeValid = false;
  99.  
  100.          /* Detach the resources we will need later */
  101.               gptr->hFinderNameString = GetDetachRsrc('STR ',kSTR_Finder);
  102.               gptr->hGetInfoSubstrString = GetDetachRsrc('STR ',kSTR_GetInfoSubstr);
  103.  
  104.          /* Load the icons that will be used for displaying */
  105. #ifdef qUseIconSuite
  106.             {    Boolean iconloadfailed=false;
  107.                 THz currzone = GetZone();
  108.  
  109.                 SetZone(SystemZone());
  110.                 /* We might want to skip this to save RAM on a non-color QD machine */
  111.                 if (PopulateIconSuite(kICNN_24bitclean,&gptr->h24bitIconSuite) ||
  112.                     PopulateIconSuite(kICNN_32bitclean,&gptr->h32bitIconSuite) ||
  113.                     PopulateIconSuite(kICNN_NotAtAllSavvy,&gptr->hUnsavvyIconSuite))
  114.                         iconloadfailed = true;
  115.                 SetZone(currzone);
  116.                 if (iconloadfailed)
  117.                     goto error_return;
  118.             }
  119. #else qUseIconSuite
  120.              gptr->h24bitIcon = GetDetachRsrc('ICN#',kICNN_24bitclean);
  121.               gptr->h32bitIcon = GetDetachRsrc('ICN#',kICNN_32bitclean);
  122.               gptr->hUnsavvyIcon = GetDetachRsrc('ICN#',kICNN_NotAtAllSavvy);
  123.  
  124.             if (!gptr->h24bitIcon || !gptr->h32bitIcon || !gptr->hUnsavvyIcon)
  125.                 goto error_return;
  126. #endif qUseIconSuite
  127.         /* Now that everything else went OK, install trap patches */
  128.             gptr->oldGet1Resource =
  129.                 (GetResourceProcPtr) NGetTrapAddress(_Get1Resource,ToolTrap);
  130.             NSetTrapAddress((long) Get1ResourceWrapper,_Get1Resource,ToolTrap);
  131.  
  132.             gptr->oldNewCWindow =
  133.                 (NewWindowProcPtr) NGetTrapAddress(_NewCWindow,ToolTrap);
  134.             NSetTrapAddress((long) NewCWindowTailPatch,_NewCWindow,ToolTrap);
  135.  
  136.             gptr->oldNewWindow =
  137.                 (NewWindowProcPtr) NGetTrapAddress(_NewWindow,ToolTrap);
  138.             NSetTrapAddress((long) NewWindowTailPatch,_NewWindow,ToolTrap);
  139.  
  140.             gptr->oldShowWindow =
  141.                 (ShowWindowProcPtr) NGetTrapAddress(_ShowWindow,ToolTrap);
  142.             NSetTrapAddress((long) ShowWindowTailPatch,_ShowWindow,ToolTrap);
  143.  
  144. #ifdef qCheckHeapUsage
  145.             DebugStr("\p;HT");
  146.         /* NOTE: You should also add in the size of the 'INIT' resource */
  147. #endif qCheckHeapUsage
  148.             return;
  149.         }
  150.     }
  151. error_return:
  152.     ShowINIT(kICNN_Unsavvy,kShowInitStdOffset);
  153. }
  154.  
  155.     /* Get a resource at boot time that we want to keep after INIT closes */
  156. PRIVATE Handle GetDetachRsrc(OSType thetype,Integer theid)
  157. {    Handle h=Get1Resource(thetype,theid);
  158.  
  159.     if (h) {
  160.         HNoPurge(h);
  161.         DetachResource(h);
  162.     }
  163.     return h;
  164. }
  165. #ifdef qUseIconSuite
  166.     /* This uses the TN #306 mechanism to archive the known icons of this id
  167.         Note, the utils can promote up from a B&W icon to color screen,
  168.         but not demote down from color */
  169. PRIVATE OSErr PopulateIconSuite(Integer resid,Handle *psuiteh)
  170. {    OSErr err;
  171.     OSType icontype[3]={'ICN#','icl8','icl4'};
  172.     Handle iconh;
  173.     Integer i;
  174.  
  175.     *psuiteh = NULL;
  176.     err = NewIconSuite(psuiteh);
  177.     for (i=0; err==noErr && i<3; i++) {
  178.         iconh = GetDetachRsrc(icontype[i],resid);
  179.         if (iconh) {
  180.             Handle newh=NULL;
  181.             err = AddIconToSuite(iconh, *psuiteh, icontype[i]);
  182.         } else
  183.             if (i==0)        // must get ICN# or else
  184.                 return resNotFound;
  185.     }
  186.     return err;
  187. }
  188. #endif qUseIconSuite
  189.  
  190.  
  191. pascal void Get1ResourceFilter(OSType thetype,Integer theid)
  192. {
  193.     if (thetype=='SIZE') {
  194.         Handle h;
  195.         TGlobalsPtr gptr = GetGlobals();
  196.         GetResourceProcPtr realtrap = gptr->oldGet1Resource;
  197.     
  198.                 // Perhaps should tail patch instead, but…
  199.         h = (*realtrap)(thetype,theid);    // so steal our own copy
  200.         if (h) {
  201.             BlockMove(*h,&gptr->lastSizeRsrc,sizeof(TSizeStruct));
  202.             gptr->lastSizeValid = true;
  203.             gptr->possibleGetInfoWindow = false;
  204.         }
  205.     }
  206. }
  207.  
  208. /* Heuristic:
  209.     Expect a certain set of conditions in order to set a couple of flags
  210.     If, at any point, things don’t look kosher, clear flags and turn
  211.         off “in suspected Get Info” mode
  212.     Yeah, we could patch MenuSelect in the Finder, etc., but…
  213.  
  214.     In deciding when/how to display the required information,
  215.     this is CERTAINLY not what I would consider a shippable
  216.     implementation.  But then, app-specific patches (rather than global
  217.     system patches) rarely are — since the interface to the system
  218.     and/or ROM are documented, while the interface within any application
  219.     is usually implementation-specific.  See Leonard Rosenthol’s Finder
  220.     QuickTime icon hack for another idea on how to do this displaying.
  221. */
  222.         /* We should put our strings in a resource, obviously */
  223. Boolean AreWeInFinder(TGlobalsPtr gptr)
  224. {    register Str31 *pcurname=gCurApName;
  225.     StringHandle h=gptr->hFinderNameString;        // English is "Finder"
  226.     Integer len=Length(*h);
  227.  
  228.     if ((Length(pcurname) == len) &&
  229.         memcmp(pcurname,*h,len+1)==0)
  230.         return true;
  231.     return false;
  232. }
  233.  
  234.     /* Common logic for NewWindowTailPatch(), NewCWindowTailPatch() */
  235. PRIVATE void DoWindowHeuristics(TGlobalsPtr gptr,Boolean visible)
  236. {
  237.     if (!gptr->lastSizeValid)
  238.         return;                            // don’t care without a 'SIZE'
  239.     
  240.     if (!gptr->possibleGetInfoWindow && !visible && 
  241.         AreWeInFinder(gptr))
  242.         gptr->possibleGetInfoWindow = true;
  243.     else
  244.         gptr->lastSizeValid = false;        // misorder, clear flag
  245. }
  246.  
  247.     /* Perhaps these should be filters, but this was a later re-design */
  248. pascal WindowPtr NewWindowTailPatch(void *wStorage,const Rect *boundsRect,ConstStr255Param title,
  249.     Boolean visible,short procID,WindowPtr behind,Boolean goAwayFlag,long refCon)
  250. {    TGlobalsPtr gptr = GetGlobals();
  251.     NewWindowProcPtr realtrap=gptr->oldNewWindow;    // don’t trust compiler
  252.     WindowPtr wp;
  253.  
  254.     wp = (*realtrap)(wStorage,boundsRect,title,visible,procID,behind,goAwayFlag,refCon);
  255.     DoWindowHeuristics(gptr,visible);
  256.     return wp;
  257. }
  258.  
  259. pascal WindowPtr NewCWindowTailPatch(void *wStorage,const Rect *boundsRect,ConstStr255Param title,
  260.     Boolean visible,short procID,WindowPtr behind,Boolean goAwayFlag,long refCon)
  261. {    TGlobalsPtr gptr = GetGlobals();
  262.     NewWindowProcPtr realtrap=gptr->oldNewCWindow;    // don’t trust compiler
  263.     WindowPtr wp;
  264.  
  265.     wp = (*realtrap)(wStorage,boundsRect,title,visible,procID,behind,goAwayFlag,refCon);
  266.     DoWindowHeuristics(gptr,visible);
  267.     return wp;
  268. }
  269.  
  270. pascal void ShowWindowTailPatch(WindowPtr theWindow)
  271. {    TGlobalsPtr gptr = GetGlobals();
  272.     ShowWindowProcPtr realtrap=gptr->oldShowWindow;
  273.  
  274.     (*realtrap)(theWindow);
  275.     if (gptr->lastSizeValid && gptr->possibleGetInfoWindow && AreWeInFinder(gptr)) {
  276.         Str255 title;
  277.         Integer len;
  278.         StringHandle h=gptr->hGetInfoSubstrString;        // English is " Info"
  279.         Integer substrlen=Length(*h);
  280.     
  281.         GetWTitle(theWindow,title);
  282.         len = Length(title);
  283.         if (memcmp(&title[len-substrlen+1],&(*h)[1],substrlen)
  284.             == 0)
  285.             PlotSavviness(gptr);
  286.     }
  287.     gptr->lastSizeValid = false;     // don’t check ever again
  288. }
  289.  
  290.     /* This is the routine that actually displays the savvy-ness indication icon */
  291. PRIVATE void PlotSavviness(TGlobalsPtr gptr)
  292. {    Rect iconrect;
  293.     Integer top=7,left=203,bottom=39,right=235;
  294.     Boolean somewhatsavvy = (gptr->lastSizeRsrc.is32BitCompatible ||
  295.         gptr->lastSizeRsrc.isHighLevelEventAware ||
  296.         gptr->lastSizeRsrc.localAndRemoteHLEvents ||
  297.         gptr->lastSizeRsrc.isStationeryAware ||
  298.         gptr->lastSizeRsrc.useTextEditServices);
  299.  
  300.         /* We could display unsavvy icon using ttDisabled (TN #306, p.2)—but we don’t */
  301.     SetRect(&iconrect, left, top, right, bottom);
  302. #ifdef qUseIconSuite
  303.     (void) PlotIconSuite(&iconrect, atNone, ttNone, 
  304.         !somewhatsavvy ? gptr->hUnsavvyIconSuite :
  305.             (gptr->lastSizeRsrc.is32BitCompatible ?
  306.             gptr->h32bitIconSuite : gptr->h24bitIconSuite));
  307. #else qUseIconSuite
  308.     PlotIcon(&iconrect, 
  309.         !somewhatsavvy ? gptr->hUnsavvyIcon :
  310.             (gptr->lastSizeRsrc.is32BitCompatible ?
  311.             gptr->h32bitIcon : gptr->h24bitIcon));
  312. #endif qUseIconSuite
  313.  
  314.     if (somewhatsavvy) {    //don’t blast unsavvy icon
  315.         if (!gptr->lastSizeRsrc.isHighLevelEventAware)
  316.             DimRect(top,left,top+5,left+3);
  317.         if (!gptr->lastSizeRsrc.localAndRemoteHLEvents)
  318.             DimRect(top,right-3,top+5,right);        // local only
  319.         if (!gptr->lastSizeRsrc.isStationeryAware)
  320.             DimRect(bottom-5,left,bottom,left+3);
  321.         if (!gptr->lastSizeRsrc.useTextEditServices)
  322.             DimRect(bottom-5,right-3,bottom,right);
  323.     }
  324. }
  325.  
  326. #define kHackGray 0xAA55AA55
  327. /* To do: support Color QD GrafPort */
  328. PRIVATE void DimRect(Integer top,Integer left, Integer bottom,Integer right)
  329. {
  330. #ifdef qUnused
  331.     Pattern    myGray;
  332.     PenState  savedPnState;
  333. #endif qUnused
  334.     Rect r;
  335.  
  336.     SetRect(&r,left,top,right,bottom);
  337. #ifndef qUnused
  338.     EraseRect(&r);
  339. #else qUnused
  340.     GetPenState(&savedPnState);
  341.     PenMode(patBic);
  342.     ((long *) myGray)[0] = kHackGray;
  343.     ((long *) myGray)[1] = kHackGray;
  344.     PenPat(myGray);
  345.     PaintRect(&r);
  346.     SetPenState(&savedPnState);
  347. #endif qUnused
  348. }
  349.